<template>
  <div class="split" style="height: 80vh; --left-pane-w: 260px">
    <div class="left">
      <div class="tree-viewport">
        <el-tree
          :key="treeKey"
          ref="treeRef"
          :data="nodes"
          node-key="id"
          :props="treeProps"
          :default-expanded-keys="expandedKeys"
          highlight-current
          :expand-on-click-node="false"
          :filter-node-method="filterNode"
          class="tree leveled asset-tree edit-form"
          style="height: 80vh"
          @node-expand="onCaretExpand"
          @node-collapse="onCaretCollapse"
        >
          <template #default="{ node, data }">
            <div
              class="node-line"
              :style="{ '--lvl-color': levelColor(data.level) }"
              @click.stop="handleNodeClick(node)"
              @dblclick.stop="handleNodeDblClick(node)"
            >
              <div class="node-left">
                <el-icon v-if="typeText(data) === '系统'"><Cpu /></el-icon>
                <el-icon v-else-if="typeText(data) === '母设备'"><Setting /></el-icon>
                <el-icon v-else-if="typeText(data) === '子设备'"><Cpu /></el-icon>
                <el-icon v-else-if="typeText(data) === '部件'"><Tools /></el-icon>
                <el-icon v-else><Cpu /></el-icon>

                <span class="font-500 name-colored" :title="dispName(data)">
                  {{ dispName(data) }}
                </span>

                <!-- 仅根节点显示：一键“展开所有/收起所有” -->
                <div class="root-tools" v-if="isRootNode(node)">
                  <!-- <span
                    class="root-arrow"
                    :class="{ open: allOpen }"
                    :title="allOpen ? '收起所有' : '展开所有'"
                    @click.stop="toggleExpandAll"
                  >
                    {{ allOpen ? "↑" : "↓" }}
                  </span> -->
                </div>
              </div>

              <div class="node-right">
                <el-tag size="small" class="tag-soft" :style="softTagStyle(typeText(data))">
                  {{ shortType(typeText(data)) }}
                </el-tag>
              </div>
            </div>
          </template>
        </el-tree>
      </div>
    </div>

    <div class="right" v-loading="rightLoading">
      <div class="actions"> 
        <el-tooltip content="新增子项" placement="top">
          <el-button circle size="small" type="success" plain @click="doAdd()">
            <el-icon><Plus /></el-icon>
          </el-button>
        </el-tooltip>
        <el-tooltip content="修改" placement="top">
          <el-button circle size="small" type="warning" plain @click="doEdit()">
            <el-icon><Edit /></el-icon>
          </el-button>
        </el-tooltip>
        <el-tooltip content="删除" placement="top">
          <el-button circle size="small" type="danger" plain @click="doRemove()">
            <el-icon><Delete /></el-icon>
          </el-button>
        </el-tooltip>
        <el-tooltip content="设备备件更换历史" placement="top">
          <el-button circle size="small" type="primary" plain @click="doHistory()">
            <el-icon><Timer /></el-icon>
          </el-button>
        </el-tooltip> 
         
      </div>

      <el-empty v-if="!detail" description="点击左侧叶子查看详情；行点击/小三角=仅展开到下一层" />
      <el-descriptions v-else :column="4" border class="kv-desc">
        <el-descriptions-item label="层级路径" :span="4">
          <div class="path-row">
          <span class="path" :title="pathText">{{ pathText || "-" }}</span> 
          <el-tooltip content="复制路径" placement="top">
            <el-button
              circle
              size="small"
              type="primary"
              plain
              @click.stop="copyPath"
            >
              <el-icon><CopyDocument /></el-icon>
            </el-button>
          </el-tooltip>
        </div>
        </el-descriptions-item>
       
        <!-- <el-descriptions-item label="层级路径" :span="3">
          <span class="path">{{ getPath ? getPath(detail.id) : detail.path || "-" }}</span>
        </el-descriptions-item> -->
        <el-descriptions-item label="设备名称">{{ fmt(detail.name) }}</el-descriptions-item>
<el-descriptions-item label="设备编码">{{ fmt(detail.code) }}</el-descriptions-item>
<el-descriptions-item label="设备规格">{{ fmt(detail.specification) }}</el-descriptions-item>
<el-descriptions-item label="设备类别">{{ fmt(detail.beType) }}</el-descriptions-item>
<el-descriptions-item label="设备材质">{{ fmt(detail.material) }}</el-descriptions-item>
<el-descriptions-item label="设备区域">{{ fmt(detail.area) }}</el-descriptions-item>
<el-descriptions-item label="设备模块">{{ fmt(detail.mokuai) }}</el-descriptions-item> 
<el-descriptions-item label="设备数量">{{ fmt(detail.quantity) + detail.unit }}</el-descriptions-item>

<!-- 有值才带单位；单位建议标准化：万 / ℃ / MPa / kW -->
<el-descriptions-item label="设备金额">{{ fmtUnit(detail.amount, "万") }}</el-descriptions-item>
<el-descriptions-item label="设计温度">{{ fmtUnit(detail.designTemp, "℃") }}</el-descriptions-item>
<el-descriptions-item label="设计压力">{{ fmtUnit(detail.designPress, "MPa") }}</el-descriptions-item>
<el-descriptions-item label="电机功率">{{ fmtUnit(detail.motorPower, "kW") }}</el-descriptions-item>

<el-descriptions-item label="搅拌方式">{{ fmt(detail.mixingType) }}</el-descriptions-item>
<el-descriptions-item label="设备品牌">{{ fmt(detail.brand) }}</el-descriptions-item>
<el-descriptions-item label="设备型号">{{ fmt(detail.model) }}</el-descriptions-item>
<el-descriptions-item label="制造厂家">{{ fmt(detail.manufacturer) }}</el-descriptions-item>

 
         
        <!-- 备件清单：逐个显示 名称 / 代码 / 可用 / 总 -->
        <el-descriptions-item label="备件信息" :span="4">
  <div class="spares-grid" :class="`cols-${totalCols}`" v-if="spareList.length">
    <!-- 表头 -->
    <div class="sp-head">名称</div>
    <div class="sp-head">编码</div>
    <div class="sp-head">当前库存</div>
    <div class="sp-head">总库存</div>
    <div class="sp-head">使用数量</div>

    <!-- 行数据 -->
    <template v-for="sp in spareList" :key="sp.id || sp.code">
      <div class="sp-cell sp-name" :title="sp?.name">{{ sp?.name ?? "-" }}</div>
      <div class="sp-cell sp-code">
        <el-tag size="small" class="code-pill" v-if="sp?.code">{{ sp.code }}</el-tag>
        <span v-else>—</span>
      </div>
      <div class="sp-cell sp-avai"><span class="num-badge">{{ sp?.stockAvailable ?? 0 }}</span></div>
      <div class="sp-cell sp-total"><span class="num-badge plain">{{ sp?.stockTotal ?? 0 }}</span></div>
      <div class="sp-cell sp-total"><span class="num-badge plain">{{ used(sp) }}</span></div>
    </template>
  </div>
  <span v-else>-</span>
</el-descriptions-item>
        <el-descriptions-item label="创建时间" :span="2">{{ detail.createTime || "-" }}</el-descriptions-item>
        <el-descriptions-item label="更新时间" :span="2">{{ detail.updateTime || "-" }}</el-descriptions-item>
        <!-- <el-descriptions-item label="更新时间">{{ detail.updateTime || "-" }}</el-descriptions-item>
        <el-descriptions-item label="备注" :span="2">{{ detail.remark || "-" }}</el-descriptions-item> -->
      </el-descriptions>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, nextTick,computed } from "vue";
import { Setting, Tools, Cpu, Plus, Edit, Delete, Timer,CopyDocument } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";

const totalCols = ref(5); 
/** props */
const props = defineProps({
  nodes: { type: Array, default: () => [] },
  detailMap: { type: [Object, Map], default: () => ({}) },
  getPath: { type: Function, default: null },
  loadDetail: { type: Function, default: null },
  onAdd: { type: Function, default: null },
  onEdit: { type: Function, default: null },
  onRemove: { type: Function, default: null },
  onHistory: { type: Function, default: null },
  onRefresh: { type: Function, default: null },
});

/** refs & state */
const treeRef = ref(null);
const treeProps = { label: "label", children: "children" };
const expandedKeys = ref([]);
const treeKey = ref(0);
const detail = ref(null);
const selectedId = ref(null);
const rightLoading = ref(false);

/** 全局展开状态（仅用于根节点自定义箭头展示“展开所有/收起所有”） */
const allOpen = ref(false);

/** 防“程序性展开”触发 caret 事件 */
const suppressAuto = ref(false);

/** 工具：名称 */
const dispName = (d) => d?.name ?? d?.label ?? "";
// 为空判断：null / undefined / "" / "   "
const isBlank = (v) =>
  v === null || v === undefined || (typeof v === "string" && v.trim() === "");

// 为空则返回 "-"
const fmt = (v, dash = "-") => (isBlank(v) ? dash : v);

// 判断是否为 "NA"（大小写不敏感）
const isNA = (v) =>
  typeof v === "string" && v.trim().toUpperCase() === "NA";

// 带单位显示：空或 "NA" 则返回 "-"
const fmtUnit = (v, unit, dash = "-") =>
  isBlank(v) || isNA(v) ? dash : `${v}${unit}`;


/** 右侧操作 */
function doAdd() { if (detail.value) props.onAdd?.(detail.value); }
function doEdit() { if (detail.value) props.onEdit?.(detail.value); }
function doRemove() { if (detail.value) props.onRemove?.(detail.value); }
function doHistory() { if (detail.value) props.onHistory?.(detail.value); }  


function doRefresh() {
  props.onRefresh?.(detail.value);
  if (detail.value?.id && props.loadDetail) {
    props.loadDetail(detail.value.id).then((r) => { if (r) detail.value = r; });
  }
}

/** 类型与颜色 */
const typeText = (d) => {
  const raw = d?.type ?? d?.typeLabel ?? d?.nodeType ?? "";
  const t = String(raw).toUpperCase();
  switch (t) {
    case "SYSTEM": return "系统";
    case "MACHINE": return "母设备";
    case "MODULE": return "子设备";
    case "COMPONENT": return "部件";
    case "PART": return "零件";
    default: return String(raw) || "—";
  }
};
const shortType = (txt) => (String(txt).length === 3 ? String(txt).slice(0, 2) : txt);
function levelColor(level) {
  const palette = ["#67C23A", "#409EFF", "#E6A23C", "#F56C6C", "#909399", "#9B59B6", "#1ABC9C", "#2D8CF0"];
  return palette[(Math.max(1, Number(level || 1)) - 1) % palette.length];
}
const TAG_COLORS = {
  系统: "#67C23A", SYSTEM: "#67C23A",
  母设备: "#409EFF", MACHINE: "#409EFF",
  子设备: "#E6A23C", MODULE: "#E6A23C",
  部件: "#F56C6C", COMPONENT: "#F56C6C",
  零件: "#909399", PART: "#909399",
  default: "#1ABC9C",
};
function hex2rgba(hex, a = 1) {
  const h = hex.replace("#", "");
  const r = parseInt(h.slice(0, 2), 16), g = parseInt(h.slice(2, 4), 16), b = parseInt(h.slice(4, 6), 16);
  return `rgba(${r},${g},${b},${a})`;
}
function getColor(type) {
  const k = String(type || "");
  return TAG_COLORS[k] || TAG_COLORS[k.toUpperCase()] || TAG_COLORS.default;
}
function softTagStyle(type) {
  const c = getColor(type);
  return { "--tag-fg": c, "--tag-bg": hex2rgba(c, 0.12), "--tag-bd": hex2rgba(c, 0.22) };
}

/** 过滤 */
function filterNode(value, data) {
  if (!value) return true;
  const v = String(value).toLowerCase();
  const base = (data._rawName || "") + (data._rawCode || "") + (data.label || "") + (data.name || "");
  return base.toLowerCase().includes(v);
}
function mapGet(id) {
  if (props.detailMap instanceof Map) return props.detailMap.get(id);
  return props.detailMap?.[id];
}

/** Tree helpers */
function getAllTreeNodes() {
  const tree = treeRef.value;
  if (!tree) return [];
  const out = [];
  function walk(node) {
    if (!node) return;
    out.push(node);
    if (Array.isArray(node.childNodes)) node.childNodes.forEach(walk);
  }
  tree.root?.childNodes?.forEach(walk);
  return out;
}
function expandAllDescendants(node) {
  if (!node) return;
  node.expand && node.expand();
  if (Array.isArray(node.childNodes)) node.childNodes.forEach(expandAllDescendants);
}
function collapseAllDescendants(node) {
  if (!node) return;
  if (Array.isArray(node.childNodes)) node.childNodes.forEach(collapseAllDescendants);
  node.collapse && node.collapse();
}
function isRootNode(node) {
  return !node?.parent || node.level === 1; // Element Plus: 根的 level=1
}

/** —— 仅对“当前节点”显示下一层（不影响其它分支） —— */
async function revealNextLevel(node) {
  const tree = treeRef.value;
  if (!node || !tree) return;
  suppressAuto.value = true;

  // 1) 展开祖先（只影响路径所需的父级）
  let p = node.parent;
  while (p) { p.expand && p.expand(); p = p.parent; }

  // 2) 展开当前节点本身
  node.expand && node.expand();
  await nextTick();

  // 3) 折叠该节点所有“孙辈及以下”，保证只露出“下一层”
  if (Array.isArray(node.childNodes)) {
    node.childNodes.forEach((child) => {
      // 先折叠孩子的所有后代
      collapseAllDescendants(child);
      // 保持孩子自身为“折叠”（仅一层可见）
      child.collapse && child.collapse();
    });
  }

  // 4) 聚焦
  tree.setCurrentKey?.(node.key);
  suppressAuto.value = false;
}

/** —— 详情加载 —— */
async function selectNodeAndShowByNode(node) {
  if (!node) return;
  const id = node.data?.id;
  if (!id) return;
  treeRef.value?.setCurrentKey(node.key);
  selectedId.value = id;
  detail.value = {};
  try {
    if (props.loadDetail) {
      const row = await props.loadDetail(id);
      console.log(row);
      console.log("selectNodeAndShowByNode");
      if (row) detail.value = row;
    } else {
      const local = mapGet(id);
      if (local) detail.value = local;
    }
  } catch {}
}

/** —— 行交互（仅影响当前节点） —— */
async function handleNodeClick(node) {
  if (!node) return;
  // 无论原来是展开还是收起，统一“只显示下一层”
  await revealNextLevel(node);
  await selectNodeAndShowByNode(node);
}
async function handleNodeDblClick(node) {
  if (!node || node.isLeaf) return;
  // 双击：如果当前已展开，改为只下一层（与单击一致）；如果收起则同样只下一层
  await revealNextLevel(node);
  await selectNodeAndShowByNode(node);
}

/** —— caret 交互（仅影响当前节点） —— */
async function onCaretExpand(data, node) {
  if (suppressAuto.value) return;
  // 根节点 caret 也不全展开，只做“当前节点下一层”
  await revealNextLevel(node);
}
async function onCaretCollapse(data, node) {
  if (suppressAuto.value) return;
  // 只收起当前节点（及其子孙），不动其它分支
  collapseAllDescendants(node);
}

/** —— 仅根节点自定义箭头：全局“展开所有/收起所有” —— */
async function toggleExpandAll() {
  const tree = treeRef.value;
  if (!tree) return;
  suppressAuto.value = true;
  if (allOpen.value) {
    // 收起所有
    getAllTreeNodes().forEach((n) => n.collapse && n.collapse());
    allOpen.value = false;
  } else {
    // 展开所有到叶子
    tree.root?.childNodes?.forEach((r) => expandAllDescendants(r));
    allOpen.value = true;
  }
  suppressAuto.value = false;
}

/** —— 初始化：显示叶子（全展开），并选中第一个叶子 —— */
async function expandAllAndSelectFirstLeaf() {
  const tree = treeRef.value;
  if (!tree) return;
  suppressAuto.value = true;

  // 展开所有
  tree.root?.childNodes?.forEach((r) => expandAllDescendants(r));
  allOpen.value = true;
  await nextTick();

  // 选中第一个“叶子”
  let firstLeaf = null;
  function findLeaf(nodes) {
    for (const n of nodes || []) {
      if (!n.childNodes || n.childNodes.length === 0) return n;
      const got = findLeaf(n.childNodes);
      if (got) return got;
    }
    return null;
  }
  firstLeaf = findLeaf(tree.root?.childNodes || []);
  suppressAuto.value = false;

  if (firstLeaf) {
    await selectNodeAndShowByNode(firstLeaf);
  } else {
    detail.value = null;
  }
}

async function expandRootAndShowOneLevel() {
  const tree = treeRef.value;
  if (!tree) return;
  suppressAuto.value = true;

  // 1) 先全部收起，保证干净的初始状态
  getAllTreeNodes().forEach((n) => n.collapse && n.collapse());

  // 2) 展开所有“根节点”，并仅展示其“下一层”
  const roots = tree.root?.childNodes || [];
  roots.forEach((r) => {
    r.expand && r.expand();              // 展开根
    // 折叠子节点的后代，保证只出现下一层
    (r.childNodes || []).forEach((child) => {
      collapseAllDescendants(child);     // 折叠孙辈及以下
      child.collapse && child.collapse();// 保证 child 自身是“收起”的（只显示为一行）
    });
  });

  // 3) 默认选中第一个根节点并加载详情（右侧显示根节点数据）
  const firstRoot = roots[0];
  if (firstRoot) {
    tree.setCurrentKey?.(firstRoot.key);
    await selectNodeAndShowByNode(firstRoot);
  } else {
    detail.value = null;
  }

  // 标记“非全局展开”
  allOpen.value = false;
  suppressAuto.value = false;
}

const pathText = computed(() => {
  const id = detail.value?.id;
  return (props.getPath ? (id ? props.getPath(id) : "") : (detail.value?.path || "")) || "";
});

// 备件列表（始终返回数组）
const spareList = computed(() => {
  const arr = detail.value?.spareInfos;
  return Array.isArray(arr) ? arr : [];
});

// 合计（始终返回 { total, available }）
const spareTotals = computed(() => {
  return spareList.value.reduce(
    (acc, s) => {
      acc.total += Number(s?.stockTotal ?? 0);
      acc.available += Number(s?.stockAvailable ?? 0);
      return acc;
    },
    { total: 0, available: 0 }
  );
});

function used(sp){
  const t = Number(sp?.stockTotal ?? 0);
  const a = Number(sp?.stockAvailable ?? 0);
  return Math.max(0, t - a);
}

async function copyPath() {
  const text = pathText.value?.trim();
  if (!text) {
    ElMessage.warning("暂无可复制的路径");
    return;
  }
  try {
    await navigator.clipboard.writeText(text);
    ElMessage.success("已复制");
  } catch (e) {
    // 兼容旧环境的兜底复制
    const ta = document.createElement("textarea");
    ta.value = text;
    ta.style.position = "fixed";
    ta.style.left = "-9999px";
    document.body.appendChild(ta);
    ta.select();
    try {
      document.execCommand("copy");
      ElMessage.success("已复制");
    } catch {
      ElMessage.error("复制失败");
    } finally {
      document.body.removeChild(ta);
    }
  }
}

/** —— nodes 变化 —— */
watch(
  () => props.nodes,
  async () => {
    expandedKeys.value = []; // 由我们手动控制展开
    treeKey.value++;
    await nextTick();
    await expandRootAndShowOneLevel();
  },
  { immediate: true, deep: true }
);
</script>

<style scoped>
.split { display: grid; grid-template-columns: 360px 1fr; gap: 12px; }
.toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.toolbar .spacer { flex: 1; }

.tree { border: 1px solid #f0f2f5; border-radius: 8px; padding: 8px 10px; background: #fff; }
.node-line { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 28px; }
.name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 260px; }
.meta { display: inline-flex; gap: 6px; flex-shrink: 0; }
.ml6 { margin-left: 6px; }

.right { background: #fff; border: 1px solid #f0f2f5; border-radius: 8px; padding: 12px; }
.path { word-break: break-all; }

/* --- 容器 --- */
.tree.leveled { border: 1px solid #eef2f6; border-radius: 10px; background: #fff; padding: 6px 8px; }
:deep(.el-tree-node__content) { height: 34px; border-radius: 8px; }
:deep(.el-tree-node__expand-icon) { color: #9aa8b3; }

/* 行内容 */
.tree-row { display: flex; align-items: center; gap: 8px; width: 100%; }
.tree-row .prefix { color: #9aa8b3; display: inline-flex; align-items: center; }
.tree-row .title { color: #3e8cf0; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1 1 auto; }
.tree-row .badges { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; }

/* 胶囊 */
.pill { display: inline-flex; align-items: center; justify-content: center; height: 20px; line-height: 20px; padding: 0 8px; font-size: 12px; border-radius: 999px; border: 1px solid transparent; user-select: none; }
.pill.lv { min-width: 24px; background: #e8f3ff; color: #3e8cf0; border-color: #d7e8ff; font-weight: 700; }
.pill.tag { background: #f5f7fa; color: #5e6b76; border-color: #e8edf2; }

/* 子数徽章 */
.dot { min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px; background: #ecf5ff; color: #409eff; font-size: 12px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid #d9ecff; }

/* 悬浮/高亮 */
:deep(.el-tree-node__content:hover) { background: #f3f7ff; }
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) { background: #eaf2ff; }

/* 目录左侧竖线装饰 */
:deep(.el-tree-node) { position: relative; }
:deep(.el-tree-node:before) {
  content: ""; position: absolute; left: 10px; top: 34px; bottom: -6px; width: 1px;
  background: linear-gradient(#edf2f7, #edf2f7); opacity: 0.6;
}
:deep(.el-tree > .el-tree-node:before) { display: none; }

.root-arrow {
  width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; font-size: 12px; line-height: 1; cursor: pointer; user-select: none;
  border: 1px solid var(--el-border-color); background: var(--el-fill-color-blank);
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.root-arrow.leaf { opacity: .45; pointer-events: none; }
.root-arrow.open { color: #e6a23c; background: #fdf6ec; border-color: #f3d19e; }
.root-arrow:not(.open) { color: #409eff; background: #ecf5ff; border-color: #b3d8ff; }
.root-arrow.open:hover { background: #faecd8; border-color: #e8c08d; }
.root-arrow:not(.open):hover { background: #e6f0ff; border-color: #8cc5ff; }

/* 树宽滚动设置 */
.left { width: 360px; min-width: 360px; }
.tree-viewport{ height: 80vh; overflow: auto; }
.wide-tree{ min-width: max-content; }
.asset-tree :deep(.el-tree-node__content){ width: auto !important; }
.asset-tree :deep(.node-line){ width: max-content; white-space: nowrap; }
.asset-tree :deep(.node-left .name-colored){ overflow: visible; text-overflow: clip; }

.asset-tree :deep(.node-line) {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 8px;
  width: 100%; white-space: nowrap; cursor: pointer;
}
.asset-tree :deep(.node-left) { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.asset-tree :deep(.node-left .name-colored) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.asset-tree :deep(.node-right) { display: inline-flex; align-items: center; gap: 6px; }

/* 同层级配色（配合 --lvl-color） */
.asset-tree :deep(.name-colored){ color: var(--lvl-color); font-weight: 600; }

/* 柔和芯片风格标签 */
.tag-soft {
  --tag-fg:#606266; --tag-bg:#f5f7fa; --tag-bd:#e4e7ed;
  color: var(--tag-fg) !important; background: var(--tag-bg) !important; border-color: var(--tag-bd) !important;
  border-radius: var(--el-border-radius-base) !important;
}

/* 左侧树字号微调 */
.asset-tree :deep(.el-tree-node__content){ font-size: 13px; font-weight: 400; }
.asset-tree :deep(.node-left .name-colored){ font-weight: 300 !important; opacity: .9; }
.asset-tree :deep(.name-colored){ font-weight: 300 !important; }

/* descriptions：固定 label 宽度 */
.kv-desc:deep(td.el-descriptions__label){ width: 140px; white-space: nowrap; vertical-align: top; }
.kv-desc:deep(td.el-descriptions__content){ word-break: break-all; white-space: normal; vertical-align: top; }
.kv-desc:deep(table.el-descriptions__table){ table-layout: fixed; }

/* 右侧容器与按钮条 */
.right { position: relative; background: #fff; border: 1px solid #f0f2f5; border-radius: 8px; padding: 44px 12px 12px; overflow: auto; }
.actions {
  position: absolute; left: 12px; top: 8px; display: inline-flex; gap: 8px; z-index: 2;
  background: rgba(255,255,255,.9); padding: 4px 6px; backdrop-filter: saturate(180%) blur(8px);
}
@media (max-width: 1024px){ .actions .btn-text { display: none; } }

:root, :host { --left-pane-w: 260px; }        /* 想多窄就改这里 */

.split { display: grid; grid-template-columns: var(--left-pane-w) 1fr; gap: 12px; }
.left  { width: var(--left-pane-w); min-width: var(--left-pane-w); }

.path-row{
  display: flex;
  align-items: center;
  gap: 8px;
}
.path-row .path{
  flex: 1 1 auto;
  word-break: break-all;
}



/* 五列：名称 / 编码 / 可用 / 总数 / 使用 */
.spares-grid{
  --name-col: minmax(140px, 1.4fr);
  --code-col: minmax(140px, 1fr);
  --num-col: 96px;
  display: grid;
  grid-template-columns: var(--name-col) var(--code-col) var(--num-col) var(--num-col) var(--num-col);
  gap: 8px 12px;
  align-items: center;
}

.spares-grid .sp-head{
  font-size: 12px; color: #909399; font-weight: 600;
  padding-bottom: 2px; border-bottom: 1px dashed #eaecef;
}
.spares-grid .sp-cell{ text-align: left; }
.spares-grid .sp-name{ font-weight: 600; }

.code-pill{
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  background: #f5f7fa !important;
  border-color: #e4e7ed !important;
  border-radius: 6px !important;
  height: 22px; display: inline-flex; align-items: center;
}

/* 数字徽章：等宽数字，三种语义色 */
.num-badge{
  display: inline-block;
  padding: 0 6px; line-height: 20px; height: 20px;
  border-radius: 6px; border: 1px solid #d9ecff; background: #ecf5ff;
  font-size: 12px; font-variant-numeric: tabular-nums;
}
.num-badge.plain{ background: #eef5ff; border-color: #d6e6ff; }       /* 总数（中性） */
.num-badge.warn{ background: #fff7e6; border-color: #ffe3bf; }       /* 使用（暖色） */

/* 小屏降级：3 列（名称/编码/数字块），数字块自动换行 */
@media (max-width: 640px){
  .spares-grid{
    grid-template-columns: 1.2fr 1fr 1fr;
  }
  .spares-grid .sp-head:nth-child(3),
  .spares-grid .sp-head:nth-child(4),
  .spares-grid .sp-head:nth-child(5){ display: none; }
}

.spares-grid.cols-4{
  grid-template-columns: var(--name-col) var(--code-col) var(--num-col) var(--num-col);
}
.spares-grid.cols-5{
  grid-template-columns: var(--name-col) var(--code-col) var(--num-col) var(--num-col) var(--num-col);
}
.spares-grid.cols-6{
  grid-template-columns: var(--name-col) var(--code-col)
                          var(--num-col) var(--num-col) var(--num-col) var(--num-col);
}

@media (max-width: 640px){
  .spares-grid{ grid-template-columns: 1.2fr 1fr; }
  .spares-grid .sp-head:nth-child(n+3){ display: none; }
}


/* 占位换行：隐藏边框/间距，只起到“补格子换行”的作用 */
.kv-desc:deep(.dl-break td){
  padding: 0 !important;
  border: none !important;
}


</style>
